package cn.iocoder.yudao.module.system.service.seatreserve;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
import cn.iocoder.yudao.module.infra.dal.dataobject.config.ConfigDO;
import cn.iocoder.yudao.module.infra.service.config.ConfigService;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.service.WeChatWorkInterface.TextCardMsgSendService;
import cn.iocoder.yudao.module.system.service.WeChatWorkInterface.TextMsgSendService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.alibaba.excel.util.StringUtils;
import com.sun.org.apache.xpath.internal.operations.Bool;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

import cn.iocoder.yudao.module.system.controller.admin.seatreserve.vo.*;
import cn.iocoder.yudao.module.system.dal.dataobject.seatreserve.SeatReserveDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import cn.iocoder.yudao.module.system.dal.mysql.seatreserve.SeatReserveMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;

/**
 * 座位预定信息 Service 实现类
 *
 * @author Warren365
 */
@Service
@Validated
@Slf4j
public class SeatReserveServiceImpl implements SeatReserveService {

    @Resource
    private SeatReserveMapper seatReserveMapper;
    @Resource
    private AdminUserService userService;
    @Resource
    private TextMsgSendService textMsgSendService;
    @Resource
    private ConfigService configService;

    @Override
   /* 插入
   * 首先判断是否需要进行人员可选座位限制：checkSeatNum（）
   * 其次
   * 1、根据预定类型ReserveTime（0/预定全天；1/预定上午；2/预定下午；）判断
   *    a)如果预定全天，分别判断上午或下午是否已被预定，如果已经预定，本次预定失败
   *        如果未预定，循环插入两条数据，上午预定和下午预定
   *    b)如果是上午/下午预定，判断是否被预定，未预定创建预定记录，如果已预订，本次预定失败
   * */
    @Transactional(rollbackFor = Exception.class)
    public Long createSeatReserve(SeatReserveSaveReqVO createReqVO) {
        /*预定类型：0/预定全天；1/预定上午；2/预定下午；*/
        String type = createReqVO.getReserveTime();
        //获取后台配置参数
        ConfigDO config = configService.getConfigByKey("SEAT_SELECTION_NUM");
        if(config.getValue()!=null){//已配置座位可选限制
            if(config.getValue().equalsIgnoreCase("1")){//座位可选数量限制启动,判断是否超出最大座位选择数量
                checkSeatNum(createReqVO);
            }
        }
        SeatReservePageReqVO pageReqVO = new SeatReservePageReqVO();
        SeatReserveDO seatReserve = BeanUtils.toBean(createReqVO, SeatReserveDO.class);
        pageReqVO.setSeatId(createReqVO.getSeatId());
        pageReqVO.setOfficeId(createReqVO.getOfficeId());
        pageReqVO.setReserveTime(createReqVO.getReserveTime());

        LocalDateTime[] reserveDate = new LocalDateTime[2];
        reserveDate[0] = createReqVO.getReserveDate().toLocalDate().atStartOfDay();
        reserveDate[1] = createReqVO.getReserveDate().with(LocalTime.MAX);
        pageReqVO.setReserveDate(reserveDate);
        List<Integer> noreservestatue = new ArrayList<>();
        noreservestatue.add(1);//正常预定状态
        noreservestatue.add(2);//已签到状态

        pageReqVO.setNoReserveStatus(noreservestatue);
        List<SeatReserveDO> seatReserveList = null;
        if(type.equalsIgnoreCase("0")){//如果是全天预定

            List<String> reserveTime = new ArrayList<>();
            reserveTime.add("1");
            reserveTime.add("2");
            pageReqVO.setReserveTimeAllday(reserveTime);
            pageReqVO.setReserveTime(null);
            seatReserveList = seatReserveMapper.selectPage(pageReqVO).getList();
            if(seatReserveList!=null &&seatReserveList.size()>0) {
                throw new RuntimeException("座位已被预定，请重新选择");
            }else{
                SeatReserveDO seatReserveOfAfternoon = BeanUtils.toBean(createReqVO, SeatReserveDO.class);
                seatReserve.setReserveTime("1");//上午
                seatReserveOfAfternoon.setReserveTime("2");//下午
                List<SeatReserveDO> seatList = new ArrayList<>();
                seatList.add(seatReserve);
                seatList.add(seatReserveOfAfternoon);
                seatReserveMapper.insertBatch(seatList);
                // 获得用户基本信息
                AdminUserDO user = userService.getUser(getLoginUserId());
                if(user!=null){
                    seatReserve.setReserveTime("0");
                    textMsgSendService.TextMsgSend(user.getRemark(),seatReserve,"reserve");
                }
            }
        }else{//如果是半天预定，不需要循环和修改预定时间段
            seatReserveList = seatReserveMapper.selectPage(pageReqVO).getList();
            if(seatReserveList!=null &&seatReserveList.size()>0) {
                throw new RuntimeException("座位已被预定，请重新选择");
            }else{
                seatReserveMapper.insert(seatReserve);
                // 获得用户基本信息
                AdminUserDO user = userService.getUser(getLoginUserId());
                if(user!=null){
                    textMsgSendService.TextMsgSend(user.getRemark(),seatReserve,"reserve");
                }
            }
        }
        return seatReserve.getId();
    }

    /*
    *根据日期获取用户所选天数有效预定座位情况
    * 1、如果本次选择为上午/下午，判断上午/下午个数不能超过用户可选量
    * 2、如果如果是全天，判断用户上午和下午组合座位数不能超过用户可选量
    * 3、用户可选量通过用户邮箱字段：Normal/Middle/High取值后台配置可选座位数量
    * */
    public Boolean checkSeatNum(SeatReserveSaveReqVO createReqVO) {
        Boolean beyondSelcet = true;
        // 获得用户基本信息
        AdminUserDO user = userService.getUser(getLoginUserId());
        //用户类型
        String seatNumType = user.getEmail();
        if(!(seatNumType.equalsIgnoreCase("normal")
                ||seatNumType.equalsIgnoreCase("middle")
                ||seatNumType.equalsIgnoreCase("high"))){//如果用户未进行配置或配置不规范，赋予正常用户可选值
            seatNumType = "Normal";
        }
        //获取后台配置参数
        ConfigDO config = configService.getConfigByKey(seatNumType);
        if (StringUtils.isNotBlank(config.getValue())&&!StringUtils.isEmpty(config.getValue())){
            /*用户可选座位数量*/
            Integer seatMaxNum  = Integer.valueOf(config.getValue());
            /*预定类型：0/预定全天；1/预定上午；2/预定下午；*/
            String type = createReqVO.getReserveTime();
            SeatReservePageReqVO pageReqVO = new SeatReservePageReqVO();
            //进行座位个数判断时是不需要绑定座位号的
            //pageReqVO.setSeatId(createReqVO.getSeatId());
            pageReqVO.setOfficeId(createReqVO.getOfficeId());
            pageReqVO.setReserveTime(createReqVO.getReserveTime());

            LocalDateTime[] reserveDate = new LocalDateTime[2];
            /*用户所选日期*/
            reserveDate[0] = createReqVO.getReserveDate().toLocalDate().atStartOfDay();
            reserveDate[1] = createReqVO.getReserveDate().with(LocalTime.MAX);
            pageReqVO.setReserveDate(reserveDate);
            List<Integer> noreservestatue = new ArrayList<>();
            /*用户座位状态*/
            noreservestatue.add(1);//正常预定状态
            noreservestatue.add(2);//已签到状态
            pageReqVO.setNoReserveStatus(noreservestatue);
            List<SeatReserveDO> seatReserveList = null;
            List<String> reserveTime = new ArrayList<>();
            reserveTime.add("1");
            reserveTime.add("2");
            pageReqVO.setReserveTimeAllday(reserveTime);
            pageReqVO.setReserveTime(null);
            seatReserveList = seatReserveMapper.selectPage(pageReqVO).getList();
            if(seatReserveList!=null &&seatReserveList.size()>0) {//存在已预订信息
                Integer morNum =0;
                Integer aftNum =0;
                Integer maxNum =0;
                /*上午预约列表*/
                List<SeatReserveDO> seatListMor = seatReserveList.stream()
                        .filter(reserve -> reserve.getReserveTime().contains("1"))
                        .collect(Collectors.toList());
                /*下午预约列表*/
                List<SeatReserveDO> seatListAft = seatReserveList.stream()
                        .filter(reserve -> reserve.getReserveTime().contains("2"))
                        .collect(Collectors.toList());
                if(seatListMor!=null){//如果上午存在预定，取出上午预定数量
                    morNum=  seatListMor.size();
                }
                if(seatListAft!=null){//如果下午预定，取出下午预订数量
                    aftNum = seatListAft.size();
                }
                //如果是全天预定，只要上午數量或下午數量大于最大数量即为超出限制
                if(type.equalsIgnoreCase("0")){
                    //取出上午或下午最大预定数量，赋值给最大预订数量
                    if(morNum>aftNum){
                        maxNum = morNum;
                    }else {
                        maxNum = aftNum;
                    }
                    if(seatMaxNum>=maxNum){//预定数量已达到最大预定个数限制
                        log.info("已超过可选上限，最大可选："+seatMaxNum+"  已预定上午："+morNum+"  下午："+aftNum);
                        throw new RuntimeException("已超过可选上限！");
                    }else{
                        log.info("未超过可选上限，最大可选："+seatMaxNum+"  已预定上午："+morNum+"  下午："+aftNum);
                    }
                }else if(type.equalsIgnoreCase("1")){//如果是上午半天预定，只需要判断上午最大预订数量
                    if(seatMaxNum>morNum) {
                        log.info("未超过上午可选上限，最大可选："+seatMaxNum+"  已预定上午："+morNum+"  下午："+aftNum);
                    }else{
                        log.info("已超过上午可选上限，最大可选："+seatMaxNum+"  已预定上午："+morNum+"  下午："+aftNum);
                        throw new RuntimeException("已超过可选上限！");
                    }
                }else if(type.equalsIgnoreCase("2")){
                    if(seatMaxNum>aftNum) {
                        log.info("未超过下午可选上限，最大可选："+seatMaxNum+"  已预定上午："+morNum+"  下午："+aftNum);
                    }else{
                        log.info("已超过下午可选上限，最大可选："+seatMaxNum+"  已预定上午："+morNum+"  下午："+aftNum);
                        throw new RuntimeException("已超过可选上限！");
                    }
                }
            }
        }else{
            throw new RuntimeException("座位限制参数未配置");
        }
        return beyondSelcet;
    }
    @Override
    public void updateSeatReserve(SeatReserveSaveReqVO updateReqVO) {
        // 校验存在
        validateSeatReserveExists(updateReqVO.getId());
        // 更新
        SeatReserveDO updateObj = BeanUtils.toBean(updateReqVO, SeatReserveDO.class);
        // 获得用户基本信息
        AdminUserDO user = userService.getUser(getLoginUserId());
        if(user!=null){
            textMsgSendService.TextMsgSend(user.getRemark(),updateObj,"cancel");
        }
        seatReserveMapper.updateById(updateObj);
    }

    @Override
    public void deleteSeatReserve(Long id) {
        // 校验存在
        validateSeatReserveExists(id);
        // 删除
        seatReserveMapper.deleteById(id);
    }

    private void validateSeatReserveExists(Long id) {
        if (seatReserveMapper.selectById(id) == null) {
            throw exception(SEAT_RESERVE_NOT_EXISTS);
        }
    }

    @Override
    public SeatReserveDO getSeatReserve(Long id) {
        return seatReserveMapper.selectById(id);
    }


    @Override
    public PageResult<SeatReserveDO> getSeatReservePage(SeatReservePageReqVO pageReqVO) {
        return seatReserveMapper.selectPage(pageReqVO);
    }

    @Override
    public List<SeatReserveDO> getSeatReserveList(Map<String,Object> pageReqVO) {
        return seatReserveMapper.selectByMap(pageReqVO);
    }

    public static void main(String[] args) {
        // 创建LocalDateTime实体 "2024-08-18 08:00"
        LocalDateTime specificDateTime = LocalDateTime.of(2024, 8, 18, 8, 0);

        // 打印创建的实体
        System.out.println("创建的LocalDateTime实体: " + specificDateTime);

        // 获取当天起始时间
        LocalDateTime startOfDay = specificDateTime.toLocalDate().atStartOfDay();

        // 打印当天起始时间
        System.out.println("当天起始时间: " + startOfDay);
        LocalDateTime endOfDay = specificDateTime.with(LocalTime.MAX);

        // 打印当天起始时间
        System.out.println("当天结束时间: " + endOfDay);
    }
}